changemaker.lite/api/dist/services/listmonk.client.js

142 lines
5.0 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.listmonkClient = void 0;
const env_1 = require("../config/env");
const logger_1 = require("../utils/logger");
// --- Client ---
class ListmonkClient {
get baseUrl() {
return env_1.env.LISTMONK_URL;
}
get authHeader() {
return 'Basic ' + Buffer.from(`${env_1.env.LISTMONK_ADMIN_USER}:${env_1.env.LISTMONK_ADMIN_PASSWORD}`).toString('base64');
}
get enabled() {
return env_1.env.LISTMONK_SYNC_ENABLED === 'true';
}
assertEnabled() {
if (!this.enabled) {
throw new Error('Listmonk sync is disabled. Set LISTMONK_SYNC_ENABLED=true to enable.');
}
}
async request(method, path, body) {
const url = `${this.baseUrl}${path}`;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const res = await fetch(url, {
method,
headers: {
'Authorization': this.authHeader,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
signal: controller.signal,
});
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`Listmonk API ${method} ${path} returned ${res.status}: ${text}`);
}
return await res.json();
}
finally {
clearTimeout(timeout);
}
}
async checkHealth() {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const res = await fetch(`${this.baseUrl}/api/health`, {
headers: { 'Authorization': this.authHeader },
signal: controller.signal,
});
return res.ok;
}
finally {
clearTimeout(timeout);
}
}
catch (err) {
logger_1.logger.warn('Listmonk health check failed:', err instanceof Error ? err.message : err);
return false;
}
}
async getLists() {
this.assertEnabled();
try {
const res = await this.request('GET', '/api/lists?per_page=all');
return res.data.results || [];
}
catch (err) {
logger_1.logger.warn('Failed to fetch Listmonk lists:', err instanceof Error ? err.message : err);
throw err;
}
}
async createList(name, type, tags) {
this.assertEnabled();
try {
const res = await this.request('POST', '/api/lists', {
name,
type,
optin: 'single',
tags,
});
return res.data;
}
catch (err) {
logger_1.logger.warn(`Failed to create Listmonk list "${name}":`, err instanceof Error ? err.message : err);
throw err;
}
}
async findSubscriberByEmail(email) {
this.assertEnabled();
try {
const query = encodeURIComponent(`subscribers.email='${email}'`);
const res = await this.request('GET', `/api/subscribers?query=${query}&per_page=1`);
const results = res.data.results;
return results && results.length > 0 ? results[0] : null;
}
catch (err) {
logger_1.logger.warn(`Failed to find subscriber ${email}:`, err instanceof Error ? err.message : err);
return null;
}
}
async createSubscriber(email, name, listIds, attribs) {
this.assertEnabled();
const res = await this.request('POST', '/api/subscribers', {
email,
name,
status: 'enabled',
lists: listIds,
attribs,
});
return res.data;
}
async updateSubscriber(id, data) {
this.assertEnabled();
const res = await this.request('PUT', `/api/subscribers/${id}`, data);
return res.data;
}
async upsertSubscriber(email, name, listIds, attribs) {
this.assertEnabled();
const existing = await this.findSubscriberByEmail(email);
if (existing) {
// Merge lists: combine existing + new, deduplicate
const existingListIds = existing.lists.map(l => l.id);
const mergedListIds = [...new Set([...existingListIds, ...listIds])];
// Merge attribs
const mergedAttribs = { ...existing.attribs, ...attribs };
return this.updateSubscriber(existing.id, {
email,
name: name || existing.name,
lists: mergedListIds,
attribs: mergedAttribs,
});
}
return this.createSubscriber(email, name, listIds, attribs);
}
}
exports.listmonkClient = new ListmonkClient();
//# sourceMappingURL=listmonk.client.js.map