npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fufulog/brevomorphic-cms-sdk

v1.0.4

Published

SDK library to bootstrap Brevo email templates and manage local mappings in Postgres, MySQL, or Firestore

Downloads

849

Readme

Brevo CMS Email Bootstrap SDK

A modular, lightweight, and robust Node.js SDK to synchronize and bootstrap Brevo email templates directly with local application backend events.

It provides an out-of-the-box system that syncs metadata from Brevo SMTP templates, saves target-event routing parameters in a local mapping database, runs Just-In-Time (JIT) sync, enforces visual guardrails, and exports plug-and-play Express controllers.


How to Install

1. Install the SDK

npm install @fufulog/brevomorphic-cms-sdk

2. Set Environment Variables

Copy the example env and fill in your credentials:

cp node_modules/@fufulog/brevomorphic-cms-sdk/env.example .env

Required variables:

| Variable | Description | | --- | --- | | BREVO_API_KEY | Your Brevo API key (xkeysib-...) | | DEFAULT_SENDER_EMAIL | Verified sender email address | | DB_TYPE | postgres, mysql, or firestore | | DATABASE_URL | Connection string (SQL) or Firebase credentials (Firestore) |

3. Create the Mapping Table

Run the appropriate schema migration for your database (see Database Setup below).

4. Bootstrap in Your App

import { EmailTemplateService, EmailTemplateController } from '@fufulog/brevomorphic-cms-sdk';
import express from 'express';

const emailService = new EmailTemplateService({
  brevoApiKey: process.env.BREVO_API_KEY,
  defaultSender: { email: process.env.DEFAULT_SENDER_EMAIL },
  dbType: 'postgres', // or 'mysql' | 'firestore'
  dbClient: yourDbClient,
});

const app = express();
app.use(express.json());
app.use('/api/cms', new EmailTemplateController(emailService).getRouter());

app.listen(3000);

5. (Optional) Add the WYSIWYG Editor Component

The SDK ships drop-in WYSIWYG editor components for Svelte and React. Copy the component files from the SDK into your frontend project:

# Svelte
cp node_modules/@fufulog/brevomorphic-cms-sdk/svelte/BrevoWysiwyg.svelte src/components/

# React
cp node_modules/@fufulog/brevomorphic-cms-sdk/react/BrevoWysiwyg.tsx src/components/
cp node_modules/@fufulog/brevomorphic-cms-sdk/react/BrevoWysiwyg.css src/components/

See WYSIWYG Editor Components for full usage details.


Features

  • JIT Local Mapping Engine: Automatic initialization of local routing templates if a new template is created directly on Brevo.
  • Outbound Send Guardrail: Built-in safeguards that silently ignore disabled templates to protect transaction processing systems.
  • Multi-Database Support: Native integration with PostgreSQL, MySQL, and Google Cloud Firestore NoSQL with zero code changes.
  • Plug-and-Play Routing: Ready-to-mount Express Router exposing CRUD, activation toggles, verified sender lookups, and webhook routes.
  • WYSIWYG Editor Components: Bundled Svelte and React editor components with source toggle, formatting toolbar, and Brevo variable injection.
  • Type Safety: Full TypeScript declarations (.d.ts) included out of the box.

1. Database Setup

SQL (PostgreSQL & MySQL)

Create the mapping ledger table using the appropriate schema block. By default, the SDK looks for the email_event_templates table.

PostgreSQL

CREATE TABLE email_event_templates (
    id SERIAL PRIMARY KEY,
    template_id INT NOT NULL UNIQUE, -- Bridges to Brevo template ID
    event_name VARCHAR(255) DEFAULT '', -- Links backend trigger key (e.g., ticket.preapproved)
    is_active BOOLEAN DEFAULT false, -- Master toggle for active sends
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

MySQL

CREATE TABLE email_event_templates (
    id INT AUTO_INCREMENT PRIMARY KEY,
    template_id INT NOT NULL UNIQUE,
    event_name VARCHAR(255) DEFAULT '',
    is_active TINYINT(1) DEFAULT 0,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

NoSQL (Firestore)

No collection schema is required. Simply create a document collection named email_event_templates (customizable) in your Firestore database. The SDK will automatically structure documents with:

  • Document ID: Stringified template ID (e.g. "42")
  • Fields:
    • template_id: number
    • event_name: string
    • is_active: boolean
    • updated_at: timestamp

2. Bootstrapping the SDK

To bootstrap the SDK in your application, instantiate EmailTemplateService by supplying a database driver instance (Postgres Pool, MySQL connection, or Firestore client instance) and the Brevo configuration.

Recipe A: PostgreSQL (using pg Pool)

import pg from 'pg';
import { EmailTemplateService } from '@fufulog/brevomorphic-cms-sdk';

const pgPool = new pg.Pool({
  connectionString: process.env.DATABASE_URL
});

// Configure the SDK using a wrapper matching { query: (sql, params) => Promise<any> }
const emailService = new EmailTemplateService({
  brevoApiKey: process.env.BREVO_API_KEY,
  defaultSender: {
    name: "Billing Desk",
    email: "[email protected]"
  },
  dbType: 'postgres',
  dbClient: pgPool, // Standard pg Pool works natively
  tableNameOrCollection: 'email_event_templates'
});

Recipe B: MySQL (using mysql2/promise Pool)

import mysql from 'mysql2/promise';
import { EmailTemplateService } from '@fufulog/brevomorphic-cms-sdk';

const mysqlPool = await mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME
});

const emailService = new EmailTemplateService({
  brevoApiKey: process.env.BREVO_API_KEY,
  defaultSender: {
    name: "Customer Support",
    email: "[email protected]"
  },
  dbType: 'mysql',
  dbClient: mysqlPool, // Standard mysql2 promise pool works natively
  tableNameOrCollection: 'email_event_templates'
});

Recipe C: Firestore NoSQL (using firebase-admin/firestore)

import { initializeApp, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
import { EmailTemplateService } from '@fufulog/brevomorphic-cms-sdk';

// Initialize Firebase SDK
initializeApp({
  credential: cert(JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT_JSON))
});

const firestoreDb = getFirestore();

const emailService = new EmailTemplateService({
  brevoApiKey: process.env.BREVO_API_KEY,
  defaultSender: {
    name: "System Gateway",
    email: "[email protected]"
  },
  dbType: 'firestore',
  dbClient: firestoreDb, // Standard Firestore client works natively
  tableNameOrCollection: 'email_event_templates'
});

3. Mounting the Routing Layer (Express Server)

Instantiate EmailTemplateController by passing your bootstrapped EmailTemplateService and mounting the routes directly inside your Express router.

import express from 'express';
import { EmailTemplateController } from '@fufulog/brevomorphic-cms-sdk';

const app = express();
app.use(express.json());

// Create and mount CMS routes
const emailController = new EmailTemplateController(emailService);
app.use('/api/cms', emailController.getRouter());

// Start Server
app.listen(3000, () => {
  console.log('🚀 Brevo CMS mounting on http://localhost:3000/api/cms');
});

Exposed Routes

| Method | Route | Description | | --- | --- | --- | | GET | /api/cms/templates | Lists templates with combined remote + local database JIT synchronization. | | GET | /api/cms/templates/:id | Returns visual parameters, subject, HTML code block, and links for a specific template. | | POST | /api/cms/templates | Creates a new draft template on Brevo & hooks up blank local DB mappings. | | PUT | /api/cms/templates/:id | Updates name, subject, HTML markup body, and local target event assignment. | | POST | /api/cms/templates/:id/toggle | Activates/deactivates template remotely on Brevo and locally inside DB mapping. | | GET | /api/cms/senders | Pulls verified sender dropdown configurations from Brevo. | | POST | /api/cms/send | Triggers test sends for a specific mapping. |


4. Operational Workflows (Outbound Sends)

In your application code, whenever a business operation completes (e.g. user welcome, ticket pre-approval), call the SDK directly to send an event email.

The SDK automatically runs event guardrails: if no active template is associated with the event, or if it has been deactivated on the dashboard, it is ignored safely.

// Welcome Event Trigger
app.post('/api/users/signup', async (req, res) => {
  const newUser = await createUser(req.body);

  // Trigger event-driven outbound send.
  // If template is inactive (is_active = false) or event mapping doesn't exist, it skips it.
  const outcome = await emailService.sendEventEmail('user.welcome', newUser.email, {
    customer_name: newUser.name,
    signup_date: new Date().toLocaleDateString()
  });

  console.log(outcome.message); // Logs status outcome safely
  res.status(201).json({ success: true, user: newUser });
});

5. Visual Form Validation Guards

When calling emailService.updateTemplate(id, data) or hitting PUT /api/cms/templates/:id, the SDK automatically protects Brevo's API by enforcing boundary conditions:

  • Blank Names: Rejected. Form fields require unique template name keys.
  • Short HTML: Brevo servers reject payloads with missing layouts. The SDK validates that raw HTML blocks must be longer than 10 characters before transmitting.

6. WYSIWYG Editor Components

The SDK ships drop-in WYSIWYG editor components for Svelte and React. These are zero-dependency source files you copy into your frontend project — no extra npm install required.

Key Features

  • Formatting Toolbar: Bold, Italic, Underline, Strikethrough, Headings, Lists, Alignment, Links
  • Source Toggle: Switch between rich-text and raw HTML editing
  • Variable Injector: Insert Brevo Twig expressions ({{ params.name }}) at cursor position
  • Twig Bracket Protection: Does not escape {, }, or % — safe for Brevo's template engine

Svelte Usage

<script>
  import BrevoWysiwyg from './BrevoWysiwyg.svelte';

  let htmlContent = '';

  const variables = [
    { label: 'Customer Name', key: 'params.name' },
    { label: 'Ticket Code', key: 'params.ticket_code' },
    { label: 'Signup Date', key: 'params.signup_date' }
  ];
</script>

<BrevoWysiwyg
  bind:value={htmlContent}
  {variables}
  placeholder="Design your email layout..."
  on:change={(e) => console.log('HTML changed:', e.detail)}
/>

React Usage

import { useState } from 'react';
import BrevoWysiwyg from './BrevoWysiwyg';

function TemplateEditor() {
  const [htmlContent, setHtmlContent] = useState('');

  const variables = [
    { label: 'Customer Name', key: 'params.name' },
    { label: 'Ticket Code', key: 'params.ticket_code' },
    { label: 'Signup Date', key: 'params.signup_date' }
  ];

  return (
    <BrevoWysiwyg
      value={htmlContent}
      onChange={setHtmlContent}
      variables={variables}
      placeholder="Design your email layout..."
    />
  );
}

Props

| Prop | Type | Default | Description | | --- | --- | --- | --- | | value | string | '' | Raw HTML content (two-way bind in Svelte, controlled in React) | | onChange | (html: string) => void | — | Callback when content changes (React only) | | variables | { label: string, key: string }[] | [] | Available Brevo template variables | | placeholder | string | 'Start designing...' | Placeholder text | | disabled | boolean | false | Disables editing |


License

Copyright [2026] [Joseph Quesnel / TicketHouse LLC]

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.